#include "sceneMain.h"
#include "game.h"
#include <SDL_image.h>
#include <string>



SceneMain::SceneMain():
    game{Game::getInstance()}
{

}

SceneMain::~SceneMain()
{
}

void SceneMain::init()
{
    // 初始化玩家飞机纹理
    player.texture = IMG_LoadTexture(game.getRenderer(), R"(D:\CPP_GameLibrary\Shooter\assets\image\SpaceShip.png)");
    if(!player.texture)
    {
        SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to load player texture: %s", IMG_GetError());
    }

    SDL_QueryTexture(player.texture, NULL, NULL, &player.width, &player.height);
    player.width /= 4;
    player.height /= 4;
    player.position.x = game.getWindowWidth() / 2 - player.width / 2;
    player.position.y = game.getWindowHeight() - player.height;

    // 初始化玩家子弹纹理
    ProjectilePlayerTemplate.texture = IMG_LoadTexture(game.getRenderer(), R"(D:\CPP_GameLibrary\Shooter\assets\image\laser-3.png)");
    if(!ProjectilePlayerTemplate.texture)
    {
        SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to load player projectile texture: %s", IMG_GetError());
    }

    SDL_QueryTexture(ProjectilePlayerTemplate.texture, NULL, NULL, &ProjectilePlayerTemplate.width, &ProjectilePlayerTemplate.height);
    ProjectilePlayerTemplate.width /= 4;
    ProjectilePlayerTemplate.height /= 4;

    // 初始化敌人飞机纹理
    enemyTemplate.texture = IMG_LoadTexture(game.getRenderer(), R"(D:\CPP_GameLibrary\Shooter\assets\image\insect-2.png)");
    if(!enemyTemplate.texture)
    {
        SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to load enemy texture: %s", IMG_GetError());
    }

    SDL_QueryTexture(enemyTemplate.texture, NULL, NULL, &enemyTemplate.width, &enemyTemplate.height);
    enemyTemplate.width /= 4;
    enemyTemplate.height /= 4;

    // 初始化随机数
    std::random_device rd; // 获取随机数种子
    gen = std::mt19937(rd()); // 使用随机数种子初始化随机数生成器
    dis = std::uniform_real_distribution<float>(0.f, 1.f); // 设置 [0.f, 1.f] 均匀分布

    // 初始化敌人子弹纹理
    ProjectileEnemyTemplate.texture = IMG_LoadTexture(game.getRenderer(), R"(D:\CPP_GameLibrary\Shooter\assets\image\bullet-1.png)");
    if(!ProjectileEnemyTemplate.texture)
    {
        SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to load enemy projectile texture: %s", IMG_GetError());
    }

    SDL_QueryTexture(ProjectileEnemyTemplate.texture, NULL, NULL, &ProjectileEnemyTemplate.width, &ProjectileEnemyTemplate.height);
    ProjectileEnemyTemplate.width /= 4;
    ProjectileEnemyTemplate.height /= 4;

    // 初始化爆炸模板
    explosionTemplate.texture = IMG_LoadTexture(game.getRenderer(), R"(D:\CPP_GameLibrary\Shooter\assets\effect\explosion.png)");
    SDL_QueryTexture(explosionTemplate.texture, NULL, NULL, &explosionTemplate.width, &explosionTemplate.height);
    // 在一个序列帧的纹理中（默认水平排列），每帧都是一个正方形，所以动画总帧数等于 纹理宽度/纹理高度
    explosionTemplate.totalFrame = explosionTemplate.width / explosionTemplate.height;
    // 因为每帧都是一个正方形，所以宽度等于高度
    explosionTemplate.height *= 2;
    explosionTemplate.width = explosionTemplate.height;

    // 初始化道具
    itemTemplate.texture = IMG_LoadTexture(game.getRenderer(), R"(D:\CPP_GameLibrary\Shooter\assets\image\bonus_life.png)");
    SDL_QueryTexture(itemTemplate.texture, NULL, NULL, &itemTemplate.width, &itemTemplate.height);
    itemTemplate.width /= 4;
    itemTemplate.height /= 4;
    itemTemplate.type = ItemType::Life;

    // 读取并播放背景音乐
    bgm = Mix_LoadMUS(R"(D:\CPP_GameLibrary\Shooter\assets\music\03_Racing_Through_Asteroids_Loop.ogg)");
    Mix_PlayMusic(bgm, -1);

    // 读取音效资源
    effectSounds.emplace("player_shoot", Mix_LoadWAV(R"(D:\CPP_GameLibrary\Shooter\assets\sound\laser_shoot4.wav)"));
    effectSounds.emplace("enemy_shoot", Mix_LoadWAV(R"(D:\CPP_GameLibrary\Shooter\assets\sound\xs_laser.wav)"));
    effectSounds.emplace("player_explod", Mix_LoadWAV(R"(D:\CPP_GameLibrary\Shooter\assets\sound\explosion1.wav)"));
    effectSounds.emplace("enemy_explod", Mix_LoadWAV(R"(D:\CPP_GameLibrary\Shooter\assets\sound\explosion3.wav)"));
    effectSounds.emplace("hit", Mix_LoadWAV(R"(D:\CPP_GameLibrary\Shooter\assets\sound\eff11.wav)"));
    effectSounds.emplace("get_item", Mix_LoadWAV(R"(D:\CPP_GameLibrary\Shooter\assets\sound\eff5.wav)"));

    // 初始化ui资源
    uiHealth = IMG_LoadTexture(game.getRenderer(), R"(D:\CPP_GameLibrary\Shooter\assets\image\Health UI Black.png)");

    // 初始化字体资源
    scoreFont = TTF_OpenFont(R"(D:\CPP_GameLibrary\Shooter\assets\font\VonwaonBitmap-12px.ttf)", 24);
}

void SceneMain::update(float deltaTime)
{
    keyboardControl(deltaTime);
    updatePlayer(deltaTime); // 更新玩家
    updateProjectiles(deltaTime); // 更新玩家子弹
    spawnEnemy(); // 生成敌机
    updateEnemies(deltaTime); // 更新敌机
    updateEnemyProjectiles(deltaTime); // 更新敌机子弹
    updateExplosions(deltaTime); // 更新爆炸效果
    updateItems(deltaTime); // 更新掉落道具
}

void SceneMain::render()
{
    // 渲染玩家子弹
    for(auto &bullet : playerProjectiles)
    {
        SDL_Rect bulletRect = {
            static_cast<int>(bullet->position.x), 
            static_cast<int>(bullet->position.y), 
            bullet->width, 
            bullet->height
        };

        SDL_RenderCopy(game.getRenderer(), bullet->texture, NULL, &bulletRect);
    }

    if(isPlayerAlive)
    {
        // 渲染玩家
        SDL_Rect playerRect = {
            static_cast<int>(player.position.x), 
            static_cast<int>(player.position.y), 
            player.width, 
            player.height
        };

        SDL_RenderCopy(game.getRenderer(), player.texture, NULL, &playerRect);
    }

    // 渲染敌机
    renderEnemies();

    // 渲染敌机子弹
    renderEnemyProjectiles();

    // 渲染掉落道具
    renderItems();

    // 渲染爆炸效果
    renderExplosions();

    // 渲染UI
    renderUI();
}

void SceneMain::clean()
{
    // 清理玩家资源
    if(player.texture)
    {
        SDL_DestroyTexture(player.texture);
        player.texture = nullptr;
    }

    // 清理玩家子弹资源
    if(ProjectilePlayerTemplate.texture)
    {
        SDL_DestroyTexture(ProjectilePlayerTemplate.texture);
        ProjectilePlayerTemplate.texture = nullptr;
    }   

    // 清理敌人资源
    if(enemyTemplate.texture)
    {
        SDL_DestroyTexture(enemyTemplate.texture);
        enemyTemplate.texture = nullptr;
    }

    for(auto &enemy : enemies)
    {
        delete enemy;
    }
    enemies.clear();

    // 清理敌机子弹资源
    if(ProjectileEnemyTemplate.texture)
    {
        SDL_DestroyTexture(ProjectileEnemyTemplate.texture);
        ProjectileEnemyTemplate.texture = nullptr;
    }

    for(auto &projectile : enemyProjectiles)
    {
        delete projectile;
    }
    enemyProjectiles.clear();

    // 清理爆炸动画资源
    if(explosionTemplate.texture)
    {
        SDL_DestroyTexture(explosionTemplate.texture);
        explosionTemplate.texture = nullptr;
    }

    for(auto& explosion: explosions)
    {
        delete explosion;
    }
    explosions.clear();    

    // 清理掉落物资源
    if(itemTemplate.texture)
    {
        SDL_DestroyTexture(itemTemplate.texture);
        itemTemplate.texture = nullptr;
    }

    for(auto& item: items)
    {
        delete item;
    }
    items.clear();

    // 清理音效资源
    for(auto& sound : effectSounds)
    {
        Mix_FreeChunk(sound.second);
    }
    effectSounds.clear();

    Mix_HaltMusic();
    Mix_FreeMusic(bgm);

    // 清理ui资源
    SDL_DestroyTexture(uiHealth);

    // 清理字体资源
    TTF_CloseFont(scoreFont);

    // 清理玩家资源
    if(player.texture)
    {
        SDL_DestroyTexture(player.texture);
        player.texture = nullptr;
    }
}

void SceneMain::handleEvent(SDL_Event *event)
{
}

void SceneMain::keyboardControl(float deltaTime)
{
    auto keyState = SDL_GetKeyboardState(NULL);

    if(isPlayerAlive)
    {
        if(keyState[SDL_SCANCODE_W])
        {
            player.position.y -= player.speed * deltaTime;
        }
        else if(keyState[SDL_SCANCODE_S])
        {
            player.position.y += player.speed * deltaTime;
        }
        else if(keyState[SDL_SCANCODE_A])
        {
            player.position.x -= player.speed * deltaTime;
        }
        else if(keyState[SDL_SCANCODE_D])
        {
            player.position.x += player.speed * deltaTime;
        }

        // 限制飞机移动范围
        if(player.position.x < 0)
        {
            player.position.x = 0;
        }
        else if(player.position.x > game.getWindowWidth() - player.width)
        {
            player.position.x = game.getWindowWidth() - player.width;
        }

        if(player.position.y < 0)
        {
            player.position.y = 0;
        }
        else if(player.position.y > game.getWindowHeight() - player.height)
        {
            player.position.y = game.getWindowHeight() - player.height;
        }

        // 发射子弹
        if(keyState[SDL_SCANCODE_J])
        {
            Uint32 currentShootTime = SDL_GetTicks();
            if(currentShootTime - player.lastShootTime > ProjectilePlayerTemplate.cooldown)
            {
                Projectile* newBullet = new Projectile(ProjectilePlayerTemplate);
                newBullet->position.x = player.position.x + player.width / 2 - newBullet->width / 2;
                newBullet->position.y = player.position.y;
                newBullet->speed = player.speed * 2;
                
                playerProjectiles.push_back(newBullet);

                player.lastShootTime = currentShootTime;

                Mix_PlayChannel(0, effectSounds["player_shoot"], 0);
            }
        }
    }
}

void SceneMain::updatePlayer(float deltaTime)
{
    if(isPlayerAlive && (player.health <= 0))
    {
        auto currentTime = SDL_GetTicks();
        Explosion* explosion = new Explosion(explosionTemplate);
        explosion->position.x = player.position.x + player.width / 2 - explosion->width / 2;
        explosion->position.y = player.position.y + player.height / 2 - explosion->height / 2;
        explosion->startTime = currentTime;

        explosions.push_back(explosion);

        isPlayerAlive = false;

        Mix_PlayChannel(-1, effectSounds["player_explod"], 0);
    }
}

void SceneMain::updateProjectiles(float deltaTime)
{

    for(auto iter = playerProjectiles.begin(); iter != playerProjectiles.end(); )
    {
        // 更新子弹位置
        auto projectile = *iter;
        projectile->position.y -= projectile->speed * deltaTime;

        // 检测子弹是否在屏幕外
        int margin = 10;
        if(projectile->position.y + margin < 0)
        {
            delete projectile;
            iter = playerProjectiles.erase(iter);
        }
        else
        {
            bool hit = false;
            for(auto& enemy: enemies)
            {
                SDL_Rect enemyRect{
                    static_cast<int>(enemy->position.x),
                    static_cast<int>(enemy->position.y),
                    enemy->width,
                    enemy->height
                };

                SDL_Rect projectileRect{
                    static_cast<int>(projectile->position.x),
                    static_cast<int>(projectile->position.y),
                    projectile->width,
                    projectile->height
                };

                if(SDL_HasIntersection(&enemyRect, &projectileRect))
                {
                    // 敌人生命值扣除
                    enemy->health -= projectile->damage;
                    // 子弹销毁
                    delete projectile;
                    iter = playerProjectiles.erase(iter);

                    hit = true;
                    break;

                    Mix_PlayChannel(-1, effectSounds["hit"], 0);
                }
            }

            if(!hit)
            {
                iter++;
            }
        }
    }
}

void SceneMain::spawnEnemy()
{
    if(!isPlayerAlive)
    return;

    // 使用 [0.f, 1.f] 随机数决定是否生成敌机， 每帧约 1/60的概率
    if(dis(gen) > 1/60.f)
    {
        return;
    }

    // 生成敌机
    Enemy* newEnemy = new Enemy(enemyTemplate);
    // 设置敌机水平位置
    newEnemy->position.x = dis(gen) * (game.getWindowWidth() - newEnemy->width);
    // 设置敌机垂直位置 (刚好在屏幕上方 不可见)
    newEnemy->position.y = -newEnemy->height;

    enemies.push_back(newEnemy);
}

void SceneMain::updateEnemies(float deltaTime)
{
    // 更新敌机位置
    for(auto iter = enemies.begin(); iter != enemies.end(); )
    {
        auto enemy = *iter;
        // 更新敌机位置
        enemy->position.y += enemy->speed * deltaTime;

        // 检测敌机是否在屏幕外
        if(enemy->position.y > game.getWindowHeight())
        {
            delete enemy;
            iter = enemies.erase(iter);
        }
        else
        {
            if(enemy->health <= 0)
            {
                enemyExplode(enemy);

                delete enemy;
                iter = enemies.erase(iter);
            }
            else
            {
                // 检测敌机与玩家是否有碰撞
                SDL_Rect enemyRect = {
                    static_cast<int>(enemy->position.x), 
                    static_cast<int>(enemy->position.y), 
                    enemy->width, 
                    enemy->height};

                    SDL_Rect playerRect = {
                        static_cast<int>(player.position.x), 
                        static_cast<int>(player.position.y), 
                        player.width, 
                        player.height};

                if(isPlayerAlive && SDL_HasIntersection(&enemyRect, &playerRect))
                {
                    player.health -= 1;

                    enemy->health = 0;
                }
                else
                {
                    spawnEnemyProjectile(enemy);
                }

                ++iter;
            }

        }
    }
}

void SceneMain::renderEnemies()
{
    for(auto& enemy: enemies)
    {
        SDL_Rect enemyRect = {
            static_cast<int>(enemy->position.x), 
            static_cast<int>(enemy->position.y), 
            enemy->width, 
            enemy->height};

            SDL_RenderCopy(game.getRenderer(), enemy->texture, nullptr, &enemyRect);
    }
}

void SceneMain::spawnEnemyProjectile(Enemy* enemy)
{
    if(!isPlayerAlive)
    return;

    Uint32 currentShootTime = SDL_GetTicks();
    if(currentShootTime - enemy->lastShootTime > ProjectileEnemyTemplate.cooldown)
    {
        EnemyProjectile* newEnemyProjectile = new EnemyProjectile(ProjectileEnemyTemplate);
        newEnemyProjectile->position.x = enemy->position.x + enemy->width / 2 - newEnemyProjectile->width / 2;
        newEnemyProjectile->position.y = enemy->position.y + enemy->height / 2;
        newEnemyProjectile->direction = getShootDirection(enemy);
        newEnemyProjectile->speed = enemy->speed * 2;

        enemyProjectiles.push_back(newEnemyProjectile);

        enemy->lastShootTime = currentShootTime;

        Mix_PlayChannel(-1, effectSounds["enemy_shoot"], 0);
    }
}

void SceneMain::updateEnemyProjectiles(float deltaTime)
{
    for(auto& iter = enemyProjectiles.begin(); iter != enemyProjectiles.end(); )
    {
        EnemyProjectile* projectile = *iter;
        // 更新敌人子弹位置
        projectile->position.x += projectile->speed * deltaTime * projectile->direction.x;
        projectile->position.y += projectile->speed * deltaTime * projectile->direction.y;

        // 判断子弹是否超出屏幕
        Uint16 margin = 10;
        if((projectile->position.x + margin < 0) || (projectile->position.x - margin > game.getWindowWidth()))
        {
            delete projectile;
            iter = enemyProjectiles.erase(iter);
        }
        else if((projectile->position.y + margin < 0) || (projectile->position.y - margin > game.getWindowHeight()))
        {
            delete projectile;
            iter = enemyProjectiles.erase(iter);
        }
        else
        {
            if(!isPlayerAlive)
            {
                iter++;
                continue;
            
            }

            SDL_Rect playerRect{
                static_cast<int>(player.position.x),
                static_cast<int>(player.position.y),
                player.width,
                player.height
            };

            SDL_Rect projectileRect{
                static_cast<int>(projectile->position.x),
                static_cast<int>(projectile->position.y),
                projectile->width,
                projectile->height
            };

            if(SDL_HasIntersection(&playerRect, &projectileRect))
            {
                // 玩家生命值扣除
                player.health -= projectile->damage;
                // 子弹销毁
                delete projectile;
                iter = enemyProjectiles.erase(iter);

                Mix_PlayChannel(-1, effectSounds["hit"], 0);
            }
            else
            {
                iter++;
            }
        }
    }
}

void SceneMain::renderEnemyProjectiles()
{
    for(auto& projectile : enemyProjectiles)
    {
        SDL_Rect bulletRect = {
            static_cast<int>(projectile->position.x), 
            static_cast<int>(projectile->position.y), 
            projectile->width, 
            projectile->height
        };

        float angle = atan2(projectile->direction.y, projectile->direction.x) * 180 / M_PI - 90;
        SDL_RenderCopyEx(game.getRenderer(), projectile->texture, NULL, &bulletRect, angle, NULL, SDL_FLIP_NONE);
    }
}

SDL_FPoint SceneMain::getShootDirection(Enemy *enemy)
{
    SDL_FPoint VecToPlayer{player.position.x - enemy->position.x, player.position.y - enemy->position.y};
    float VecLength = sqrt(VecToPlayer.x * VecToPlayer.x + VecToPlayer.y * VecToPlayer.y);

    return {VecToPlayer.x / VecLength, VecToPlayer.y / VecLength};
}

void SceneMain::enemyExplode(Enemy *enemy)
{
    // 生成爆炸特效
    auto currentTime = SDL_GetTicks();
    Explosion* explosion = new Explosion(explosionTemplate);
    explosion->position.x = enemy->position.x + enemy->width / 2 - explosion->width / 2;
    explosion->position.y = enemy->position.y + enemy->height / 2 - explosion->height / 2;
    explosion->startTime = currentTime;

    explosions.push_back(explosion);

    // 生成掉落物
    if(dis(gen) < 0.5)
    {
        Item* item = new Item(itemTemplate);
        item->position.x = enemy->position.x + enemy->width / 2 - item->width / 2;
        item->position.y = enemy->position.y + enemy->height / 2 - item->height / 2;
  
        float randomRadian = dis(gen) * 2 * M_PI;
        item->direction.x = cos(randomRadian);
        item->direction.y = sin(randomRadian);

        items.push_back(item);
    }

    Mix_PlayChannel(-1, effectSounds["enemy_explod"], 0);

    score += 10;
}

void SceneMain::updateExplosions(float deltaTime)
{
    auto currentTime = SDL_GetTicks();
    for(auto iter = explosions.begin(); iter != explosions.end();)
    {
        Explosion* explosion = *iter;
        // 根据时间差和帧率 计算当前帧索引
        explosion->currentFrame = (currentTime - explosion->startTime) * explosion->FPS / 1000.0f;
        // 检查动画是否播完
        if(explosion->currentFrame >= explosion->totalFrame)
        {
            delete explosion;
            iter = explosions.erase(iter);
        }
        else
        {
            ++iter;
        }

    }
}

void SceneMain::renderExplosions()
{
    for(auto& explosion : explosions)
    {
        // 定义纹理上的范围
        SDL_Rect srcRect = {explosion->currentFrame * explosion->width, 0, explosion->width/2, explosion->height/2};
        // 定义屏幕上的范围
        SDL_Rect dstRect = {
            static_cast<int>(explosion->position.x), 
            static_cast<int>(explosion->position.y), 
            explosion->width, 
            explosion->height};

        // 绘制纹理
        SDL_RenderCopy(game.getRenderer(), explosion->texture, &srcRect, &dstRect);
    }
}

void SceneMain::updateItems(float deltaTime)
{
    for(auto iter = items.begin(); iter != items.end(); )
    {
        Item* item = *iter;

        item->position.x += item->speed * deltaTime * item->direction.x;
        item->position.y += item->speed * deltaTime * item->direction.y;

        if((item->position.x < 0) || (item->position.x + item->width > game.getWindowWidth()))
        {
            if(item->bounceCount > 0)
                {
                    item->direction.x = -item->direction.x;
                    --item->bounceCount;
                }
            else
            {
                delete item;
                iter = items.erase(iter);
                continue;
            }
        }
        if((item->position.y < 0) || (item->position.y + item->height > game.getWindowHeight()))
        {
            if(item->bounceCount > 0)
            {
                item->direction.y = -item->direction.y;
                --item->bounceCount;
            }
            else
            {
                delete item;
                iter = items.erase(iter);
                continue;
            }
        }

        // 判断与玩家重叠
        SDL_Rect playerRect = {
            static_cast<int>(player.position.x), 
            static_cast<int>(player.position.y),
            player.width, 
            player.height
        };

        SDL_Rect itemRect = {
            static_cast<int>(item->position.x), 
            static_cast<int>(item->position.y),
            item->width, 
            item->height
        };

        if(SDL_HasIntersection(&playerRect, &itemRect))
        {
            playerGetItem(item);
            delete item;
            iter = items.erase(iter);
            continue;
        }
 
        ++iter;
    }
};

void SceneMain::renderItems()
{
    for(auto& item: items)
    {
        SDL_Rect itemRect = {
            static_cast<int>(item->position.x), 
            static_cast<int>(item->position.y),
            item->width, 
            item->height
        };

        SDL_RenderCopy(game.getRenderer(), item->texture, NULL, &itemRect);
    }
};

void SceneMain::playerGetItem(Item *item)
{
    if(!isPlayerAlive)
        return;

    switch(item->type)
    {
        case ItemType::Life:
            player.health += 1;
            if(player.health > player.maxHealth)
                player.health = player.maxHealth;
            break;
        case ItemType::Shield:
            break;
        case ItemType::Time:
            break;
    }

    Mix_PlayChannel(-1, effectSounds["get_item"], 0);

    score += 5;
}

void SceneMain::renderUI() 
{
    int x = 10;
    int y = 10;
    int offset = 40;
    int size = 32;

    // 设置纹理颜色 颜色减淡
    SDL_SetTextureColorMod(uiHealth, 100,100,100);
    for(int i = 0; i < player.maxHealth; ++i)
    {
        SDL_Rect rect = {x + i * offset, y, size, size};
        SDL_RenderCopy(game.getRenderer(), uiHealth, NULL, &rect);
    }   

    if(isPlayerAlive)
    {
        // 设置纹理颜色 颜色不变
        SDL_SetTextureColorMod(uiHealth, 255,255,255);
        for(int i = 0; i < player.health; ++i)
        {
            SDL_Rect rect = {x + i * offset, y, size, size};
            SDL_RenderCopy(game.getRenderer(), uiHealth, NULL, &rect);
        }   
    }

    
    // 渲染字体
    auto text = "SCORE:" + std::to_string(score);
    SDL_Color color{255, 255, 255, 255};
    SDL_Surface* surface = TTF_RenderUTF8_Solid(scoreFont, text.c_str(), color);
    SDL_Texture* texture = SDL_CreateTextureFromSurface(game.getRenderer(), surface);
    SDL_Rect rect{game.getWindowWidth() - 10 - surface->w, 10, surface->w, surface->h};
    SDL_RenderCopy(game.getRenderer(), texture, NULL, &rect);
    // 释放资源，防止内存泄漏
    SDL_FreeSurface(surface);
    SDL_DestroyTexture(texture);
}

